﻿using System.Collections.Generic;
using UnityEngine;

namespace AI.Graph {


    public class FieldOfView : MonoBehaviour {

        [SerializeField]
        private float m_viewRadius = 2;

        [Range (0, 360), SerializeField]
        private float m_viewAngle = 60;

        [SerializeField]
        private LayerMask m_targetMask;

        [SerializeField]
        private LayerMask m_obstacleMask;

        [SerializeField]
        private FieldOfViewMesh m_mesh = null;

        public List<GameObject> visibleTargets = new List<GameObject> ();


        public float viewRadius {
            get { return m_viewRadius; }
            set { m_viewRadius = value; }
        }

        public float viewAngle {
            get { return m_viewAngle; }
            set { m_viewAngle = value; }
        }

        public LayerMask targetMask {
            get { return m_targetMask; }
            set { m_targetMask = value; }
        }


        public LayerMask obstacleMask {
            get { return m_obstacleMask; }
            set { m_obstacleMask = value; }
        }


        public bool drawMesh {
            get { return m_mesh && m_mesh.gameObject.activeSelf; }
            set {
                if (m_mesh != null) {
                    m_mesh.gameObject.SetActive (value);
                }
            }
        }


        /// <summary>
        /// Returns all visible targets.
        /// </summary>
        public void FindVisibleTargets (ref List<GameObject> visibleTargets) {
            FindVisibleTargets (targetMask, obstacleMask, viewRadius, viewAngle, ref visibleTargets);
        }


        /// <summary>
        /// Returns all visible targets.
        /// </summary>
        public void FindVisibleTargets (LayerMask targetMask, LayerMask obstacleMask, float viewRadius, float viewAngle, ref List<GameObject> visibleTargets) {
            visibleTargets.Clear ();
            this.visibleTargets.Clear ();
            Collider[] targetsInViewRadius = Physics.OverlapSphere (transform.position, viewRadius, targetMask);

            for (int i = 0; i < targetsInViewRadius.Length; i++) {
                Transform target = targetsInViewRadius[i].transform;
                Vector3 dirToTarget = (target.position - transform.position).normalized;
                if (Vector3.Angle (transform.forward, dirToTarget) < viewAngle / 2) {
                    float dstToTarget = Vector3.Distance (transform.position, target.position);
                    if (!Physics.Raycast (transform.position, dirToTarget, dstToTarget, obstacleMask)) {
                        visibleTargets.Add (target.gameObject);
                        this.visibleTargets.Add (target.gameObject);
                    }
                }
            }
        }


        void LateUpdate () {
            if (drawMesh) {
                m_mesh.GenerateFieldOfViewMesh (viewAngle, viewRadius, obstacleMask);
            }
        }

    }


}